package com.leyou.order.service;

import com.leyou.common.auth.pojo.UserInfo;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exceptions.LyException;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.IdWorker;
import com.leyou.item.client.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.order.dto.CartDTO;
import com.leyou.order.dto.OrderDTO;
import com.leyou.order.entity.Order;
import com.leyou.order.entity.OrderDetail;
import com.leyou.order.entity.OrderLogistics;
import com.leyou.order.enums.OrderStatusEnum;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderLogisticsMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.utils.PayHelper;
import com.leyou.order.utils.UserHolder;
import com.leyou.order.vo.OrderDetailVO;
import com.leyou.order.vo.OrderLogisticsVO;
import com.leyou.order.vo.OrderVO;
import com.leyou.user.client.UserClient;
import com.leyou.user.dto.AddressDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 虎哥
 */
@Slf4j
@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper detailMapper;
    @Autowired
    private OrderLogisticsMapper logisticsMapper;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private ItemClient itemClient;

    @Autowired
    private UserClient userClient;

    @Transactional
    public Long createOrder(OrderDTO orderDTO) {

        // 1.新增order表
        Order order = new Order();
        // 1.1.订单编号
        long orderId = idWorker.nextId();
        order.setOrderId(orderId);

        List<OrderDetail> detailList = new ArrayList<>();
        // 1.2.金额信息
        List<CartDTO> carts = orderDTO.getCarts();
        Map<Long, Integer> skuMap = carts.stream().collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));
        // 1.2.1.获取sku的id的集合
        List<Long> idList = carts.stream().map(CartDTO::getSkuId).collect(Collectors.toList());
        // 1.2.2.查询sku
        List<SkuDTO> skuList = itemClient.querySkuListByIds(idList);
        // 1.2.3.计算价格
        long total = 0L;
        for (SkuDTO sku : skuList) {
            // 计算总价
            int num = skuMap.get(sku.getId());
            total += sku.getPrice() * num;
            // 封装OrderDetail
            OrderDetail detail = new OrderDetail();
            detail.setTitle(sku.getTitle());
            detail.setSkuId(sku.getId());
            detail.setPrice(sku.getPrice());
            detail.setNum(num);
            detail.setOwnSpec(sku.getOwnSpec());
            detail.setImage(StringUtils.substringBefore(sku.getImages(), ","));
            detail.setOrderId(orderId);
            detailList.add(detail);
        }
        // 1.2.4.赋值
        order.setTotalFee(total);
        order.setPostFee(0L);
        order.setActualFee(order.getTotalFee() + order.getPostFee());
        order.setPaymentType(orderDTO.getPaymentType());

        // 1.3.用户信息
        UserInfo user = UserHolder.getUser();
        order.setUserId(user.getId());

        // 1.4.状态信息
        order.setStatus(OrderStatusEnum.INIT.value());

        // 1.5.写入数据库
        int count = orderMapper.insertSelective(order);
        if (count != 1) {
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }

        // 2.新增orderDetail表
        count = detailMapper.insertList(detailList);
        if (count != detailList.size()) {
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }

        // 3.新增OrderLogistics表
        Long addressId = orderDTO.getAddressId();
        // 3.1.根据地址id查询地址信息
        AddressDTO address = userClient.queryAddressById(user.getId(), addressId);
        // 3.2.封装成Logistics对象
        OrderLogistics logistics = BeanHelper.copyProperties(address, OrderLogistics.class);
        logistics.setOrderId(orderId);
        // 3.3.写入数据库
        count = logisticsMapper.insertSelective(logistics);
        if (count != 1) {
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }

        // 4.减库存
        try {
            itemClient.minusStock(skuMap);
        }catch (Exception e){
            throw new LyException(ExceptionEnum.STOCK_NOT_ENOUGH, e);
        }

        // 5.扣减优惠券
        return orderId;
    }

    public OrderVO queryOrderById(Long orderId) {
        // 1.根据id查询订单
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (order == null) {
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        OrderVO orderVO = BeanHelper.copyProperties(order, OrderVO.class);
        // 2.查询订单详情
        List<OrderDetailVO> detailVOList = queryDetailByOrderId(orderId);
        orderVO.setDetailList(detailVOList);
        // 3.查询订单物流
        OrderLogisticsVO logistics = queryLogisticByOrderId(orderId);
        orderVO.setLogistics(logistics);
        return orderVO;
    }

    private OrderLogisticsVO queryLogisticByOrderId(Long orderId) {
        OrderLogistics logistics = logisticsMapper.selectByPrimaryKey(orderId);
        if (logistics == null) {
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        return BeanHelper.copyProperties(logistics, OrderLogisticsVO.class);
    }

    private List<OrderDetailVO> queryDetailByOrderId(Long orderId) {
        OrderDetail record = new OrderDetail();
        record.setOrderId(orderId);
        List<OrderDetail> list = detailMapper.select(record);
        if (CollectionUtils.isEmpty(list)) {
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        return BeanHelper.copyWithCollection(list, OrderDetailVO.class);
    }

    @Autowired
    private PayHelper payHelper;

    public String getPayUrl(Long orderId) {
        // TODO 0.尝试从Redis中获取URL地址，如果有，直接返回

        // 1.查询订单
        Order order = orderMapper.selectByPrimaryKey(orderId);
        // 2.判断订单状态
        if (!order.getStatus().equals(OrderStatusEnum.INIT.value())) {
            // 订单已经支付或者关闭
            throw new LyException(ExceptionEnum.INVALID_ORDER_STATUS);
        }
        // 3.获取总金额
        Long actualFee = order.getActualFee();
        // 4.商品描述
        String desc = "乐优商城";
        String url = payHelper.generatePayUrl(orderId, actualFee, desc);

        // TODO 5.把url地址缓存在Redis中，提高效率
        return url;
    }

    public void handleNotify(Map<String, String> data) {
        try {
            // 1.校验签名
            payHelper.checkSignature(data);
            // 2.校验通信标识
            payHelper.checkReturnCode(data);
            // 3.校验业务标识
            payHelper.checkResultCode(data);

            // 4.校验订单的金额
            // 4.1.获取订单编号及订单的金额
            String tradeNo = data.get("out_trade_no");
            String totalFee = data.get("total_fee");
            if(StringUtils.isBlank(tradeNo) || StringUtils.isBlank(totalFee)){
                throw new RuntimeException("订单编号或金额为空！");
            }
            Long orderId = Long.valueOf(tradeNo);
            Long total = Long.valueOf(totalFee);
            // 4.2.从数据库中取出订单金额
            Order order = orderMapper.selectByPrimaryKey(orderId);
            Long actualFee = order.getActualFee();
            // 4.3.判断金额
            if(!actualFee.equals(total)){
                throw new RuntimeException("订单金额有误，我要报警了！");
            }
            // 5.判断订单状态，保证业务幂等
            if(!order.getStatus().equals(OrderStatusEnum.INIT.value())){
                // 订单已经支付，重复通知,忽略
                return;
            }
            // 6.支付成功，修改订单状态为已支付
            Order record = new Order();
            record.setOrderId(orderId);
            record.setStatus(OrderStatusEnum.PAY_UP.value());
            record.setPayTime(new Date());
            int count = orderMapper.updateByPrimaryKeySelective(record);
            if(count != 1){
                throw new LyException(ExceptionEnum.UPDATE_OPERATION_FAIL);
            }
            log.info("微信支付回调处理成功，订单编号:[{}]", orderId);
        } catch (Exception e) {
            log.error("微信支付回调异常，原因:{}", e.getMessage(), e);
            throw new LyException(ExceptionEnum.INVALID_NOTIFY_PARAM);
        }
    }

    public Integer queryOrderState(Long orderId) {
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (order == null) {
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        return order.getStatus();
    }
}
